#ifndef FS_EXT_H
#define FS_EXT_H
#include "fs.h"
#include <vector>
class Inode;
class File;
class SuperBlock;
class Buffer;
class ParaForShare;
template <typename T> class PtrList;
template <typename T> class PtrArray;
class FsExt : public FS
{
public:
    FsExt();
	FsExt(uint32 start_sector,SuperBlock& super_block,uint8 type,HANDLE disk_handle);
    ~FsExt();
	bool copy(const wint16* from_path,const wint16* to_path) const;
	bool copy(uint32 inode_num,const wint16* to_path) const;

	PtrArray<File> scanDir(uint32 inode_num) const;
	PtrArray<File> scanDir(const wint16* path) const;

	bool checkDir(uint32 inode_num) const;
	bool checkDir(const wint16* path) const;
private:
    uint32 block_size; 
    uint16 inode_size;
    uint32 inodes_per_group;
    uint32 group_desc_start;
    uint32 desc_size;
    uint32 desc_count_per_block; 
	uint32 total_block_count_low;
	uint32 total_block_count_high;
private:
	bool copy(const Inode& inode,const wint16* to_path) const;
	void copyFile(const Inode& inode,const wint16* file_path) const;
	void copyDir(PtrArray<File>& files,const wint16* file_path) const;
	PtrArray<File> scanDir(const Inode& inode) const;
	bool checkDir(const Inode& inode) const;
	const Inode findFile(const wint16* file_path) const;

	void handle3(ParaForShare* para) const;
	void handleInIndblocks(ParaForShare* para)  const;
	void handleInAddrBlock(ParaForShare* para) const;
	void handle4(ParaForShare* para) const;
	void handleInExtentIdx(ParaForShare* para) const;

	void scanDirInBlocks(ParaForShare* para) const;
	void checkDirInBlocks(ParaForShare* para) const;
	void findFileInBlocks(ParaForShare* para) const;
	void copyFileInBlocks(ParaForShare* para) const;

	PtrArray<File> scanDirWithRecursion(const Inode& inode,uint32* total_file_size) const;
	void scanDirWithRecursionInBlocks(ParaForShare* para) const;

	void groupBlockNum(const uint32* start_block_num,std::vector<const uint32*>& block_nums,uint32 block_count) const;
	void readBlocks(uint64 start_block_num,Buffer& buffer,uint32 block_count) const;
	const Inode readInode(uint32 inode_num) const;
	bool isBlockValid(uint64 block_num) const;
};

class ParaForShare
{
	friend class FsExt;
protected:
	typedef void (FsExt::*HandleWay)(ParaForShare*) const;
	ParaForShare(const Inode* pinode_,HandleWay handle_way):
	pinode(pinode_),level(0),block_num(0),block_count(0),is_indblock(true),handle_way(handle_way){}
	const Inode* pinode;
	uint32 level;
	uint64 block_num;
	uint32 block_count;
	bool is_indblock;
	HandleWay handle_way;
};
class ParaForScanDir:public ParaForShare
{
	friend class FsExt;
protected:
	ParaForScanDir(const Inode* pinode_,PtrList<File>* files_,HandleWay handle_way):
	   ParaForShare(pinode_,handle_way),files(files_){}
	PtrList<File>* files;

};
class ParaForScanDirWithRecursion:public ParaForScanDir
{
	friend class FsExt;
private:
	ParaForScanDirWithRecursion(const Inode* pinode_,PtrList<File>* files_,uint32* file_size_,HandleWay handle_way):
	   ParaForScanDir(pinode_,files_,handle_way),file_block_count(file_size_){}
	uint32* file_block_count;
};
class ParaForCheckDir:public ParaForShare
{
	friend class FsExt;
private:
	ParaForCheckDir(const Inode* pinode_,HandleWay handle_way):ParaForShare(pinode_,handle_way){}
};
class ParaForFindFile:public ParaForShare
{
	friend class FsExt;
private:
	ParaForFindFile(const Inode* pinode_,Buffer* file_name_,HandleWay handle_way):
	   ParaForShare(pinode_,handle_way),file_name(file_name_){}
	Buffer* file_name;
};
class ParaForCopyFile:public ParaForShare
{
	friend class FsExt;
private:
	ParaForCopyFile(const Inode* pinode_,HANDLE hfile_,uint64 file_block_count_,HandleWay handle_way):
	   ParaForShare(pinode_,handle_way),hfile(hfile_),file_block_count(file_block_count_){}
	HANDLE hfile;
	uint32 file_block_count;
};

#endif // FS_EXT_H
